package com.bfly.mall.order.service.impl;

import com.bfly.common.util.DateUtil;
import com.bfly.common.util.StringUtil;
import com.bfly.core.base.service.BaseServiceImpl;
import com.bfly.core.context.IpThreadLocal;
import com.bfly.core.enums.AccessRole;
import com.bfly.core.enums.SysError;
import com.bfly.core.exception.ServiceResponseException;
import com.bfly.mall.admin.entity.Admin;
import com.bfly.mall.order.dao.OrderRefundMapper;
import com.bfly.mall.order.dto.OrderRefundFormDTO;
import com.bfly.mall.order.entity.Order;
import com.bfly.mall.order.entity.OrderLogs;
import com.bfly.mall.order.entity.OrderRefund;
import com.bfly.mall.order.enums.*;
import com.bfly.mall.order.service.IOrderLogsService;
import com.bfly.mall.order.service.IOrderRefundService;
import com.bfly.mall.order.service.IOrderService;
import com.bfly.mall.wechat.minipro.dto.WeChatRefundOrderResponse;
import com.bfly.mall.wechat.minipro.service.WeChatMiniProOrderApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 长沙商脉科技有限公司
 * @date 2020/10/8 0:04
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
public class OrderRefundServiceImpl extends BaseServiceImpl<OrderRefund, Integer> implements IOrderRefundService {

    @Autowired
    private OrderRefundMapper refundMapper;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private IOrderLogsService orderLogsService;

    private Order getOrder(String orderNo) {
        Order order = orderService.getOrder(orderNo);
        return order;
    }

    /**
     * 生成退款单号
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/12/12 1:03
     */
    public String createRefundNo() {
        String refundNo;
        while (true) {
            refundNo = "R" + DateUtil.getCurrentDateTime().concat(StringUtil.getRandomNumber(12));
            Map<String, Object> param = new HashMap<>(1);
            param.put("refund_no", refundNo);
            long count = getCount(param);
            if (count > 0) {
                continue;
            }
            break;
        }
        return refundNo;
    }

    @Override
    public OrderRefund getOrderRefundByRefundNo(String refundNo) {
        return refundMapper.getOrderRefundByRefundNo(refundNo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyRefund(String orderNo, RefundTypeEnum typeEnum, String reason, int opId, String opName, AccessRole role) {
        Order order = getOrder(orderNo);
        if (typeEnum == null) {
            throw new ServiceResponseException(SysError.PARAM_ERROR, "参数错误!");
        }
        if (order.isCanApplyRefund()) {
            OrderLogs logs = new OrderLogs();
            logs.setRemark(reason);
            if (typeEnum == RefundTypeEnum.MONEY) {
                // 退款操作直接修改订单状态为待退款
                orderService.editPayStatus(orderNo, PayStatusEnum.WAIT_REFUND);
                logs.setType(OrderOpTypeEnum.REQUEST_REFUND_MEMBER.getId());
            } else if (typeEnum == RefundTypeEnum.MONEY_PRODUCT) {
                // 退款退货操作修改订单状态为待退款，商家待收货
                orderService.editPayStatus(orderNo, PayStatusEnum.WAIT_REFUND);
                orderService.editExpressStatus(orderNo, ExpressStatusEnum.RETURN_WAIT_RECEIVE);
                logs.setType(OrderOpTypeEnum.REQUEST_REFUND_PRODUCT_MEMBER.getId());
            }

            // 退款申请日志
            OrderRefund refundLog = new OrderRefund();
            refundLog.setRefundNo(createRefundNo());
            refundLog.setOrderNo(order.getOrderNo());
            refundLog.setApplyReason(reason);
            refundLog.setOpId(opId);
            refundLog.setOpName(opName);
            refundLog.setOpType(role.getId());
            refundLog.setOrderPrice(order.getPayPrice());
            refundLog.setRefundPrice(new BigDecimal(0));
            refundLog.setCreateDate(new Date());
            refundLog.setStatus(RefundStatusEnum.WAIT.getId());
            super.save(refundLog);

            // 记录订单日志
            logs.setOperatorId(opId);
            logs.setOperatorName(opName);
            logs.setOrderNo(orderNo);
            logs.setCreateDate(new Date());
            logs.setCreateIp(IpThreadLocal.get());
            orderLogsService.save(logs);
            return;
        }
        String message = String.format("状态为 %s %s %s 的订单不能做申请退款或退货操作!", order.getStatusName(), order.getPayStatusName(), order.getExpressStatusName());
        throw new ServiceResponseException(SysError.ERROR, message);
    }

    @Override
    public OrderRefund getLatestOrderRefund(String orderNo) {
        return refundMapper.getLatestOrderRefund(orderNo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void shopKeeperProcessRefundOrder(Admin admin, OrderRefundFormDTO formDTO) {
        OrderRefund refund = getOrderRefundByRefundNo(formDTO.getRefundNo());
        if (refund.getStatus() != RefundStatusEnum.PASS.getId()) {
            RefundStatusEnum statusEnum = RefundStatusEnum.getStatus(refund.getStatus());
            String message = String.format("退款单状态为 %s 不能做退款操作!", statusEnum.getName());
            throw new ServiceResponseException(SysError.ERROR, message);
        }
        String orderNo = refund.getOrderNo();
        Order order = getOrder(orderNo);
        if (!order.isCanRefund()) {
            String message = String.format("状态为 %s %s %s 的订单不能做退款操作!", order.getStatusName(), order.getPayStatusName(), order.getExpressStatusName());
            throw new ServiceResponseException(SysError.ERROR, message);
        }

        if (formDTO.getAmount().compareTo(order.getPayPrice()) > 0) {
            throw new ServiceResponseException(SysError.ERROR, "退款金额不能大于订单的支付金额!");
        }

        // 发起微信退款操作 并回写退款单号
        WeChatRefundOrderResponse refundOrderResponse = WeChatMiniProOrderApi.refundOrderFromWeChat(refund.getRefundNo(), orderNo, order.getTradeNo(), formDTO.getAmount(), formDTO.getRemark());
        refund.setRefundId(refundOrderResponse.getRefund_id());

        // 保存订单退款退货操作日志
        OrderLogs logs = new OrderLogs();
        logs.setCreateIp(IpThreadLocal.get());
        logs.setCreateDate(new Date());
        logs.setOrderNo(orderNo);

        logs.setType(OrderOpTypeEnum.REFUND_SHOPKEEPER.getId());
        logs.setOperatorId(admin.getId());
        logs.setOperatorName(admin.getUserName());
        logs.setRemark(formDTO.getRemark());
        orderLogsService.save(logs);

        refund.setProgressStatus(RefundProgressEnum.PROGRESSING.getId());       //退款中
        refund.setRemark(formDTO.getRemark());
        refund.setRefundPrice(formDTO.getAmount());
        refund.setRefundMethod(order.getPayType());     // 退款金额原路返回
        refund.setUpdateDate(new Date());
        super.edit(refund);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void shopKeeperAgreeRefundOrder(Admin admin, String refundNo) {
        OrderRefund refund = checkRefundForOp(refundNo);
        Order order = getOrder(refund.getOrderNo());
        // 确认退款操作
        if (!order.isCanRefund() && !order.isCanConfirmReceiveShopKeeper()) {
            String message = String.format("状态为 %s %s %s 的订单不能做退款/退货操作!", order.getStatusName(), order.getPayStatusName(), order.getExpressStatusName());
            throw new ServiceResponseException(SysError.ERROR, message);
        }

        // 保存订单退款退货操作日志
        OrderLogs logs = new OrderLogs();
        logs.setCreateIp(IpThreadLocal.get());
        logs.setCreateDate(new Date());
        logs.setOrderNo(order.getOrderNo());
        // 门店同意退款
        logs.setType(OrderOpTypeEnum.REQUEST_REFUND_CONFIRM_SHOPKEEPER.getId());
        logs.setOperatorId(admin.getId());
        logs.setOperatorName(admin.getUserName());
        orderLogsService.save(logs);

        // 修改订单的退款申请状态为“同意退款”
        refund.setStatus(RefundStatusEnum.PASS.getId());
        refund.setProgressStatus(RefundProgressEnum.UN_PROGRESS.getId());
        refund.setUpdateDate(new Date());
        super.edit(refund);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void shopKeeperRejectRefundOrder(Admin admin, String refundNo, String remark) {
        OrderRefund refund = checkRefundForOp(refundNo);
        Order order = getOrder(refund.getOrderNo());
        // 驳回退款操作
        if (!order.isCanRejectRefund()) {
            String message = String.format("状态为 %s %s %s 的订单不能做退款申请驳回操作!", order.getStatusName(), order.getPayStatusName(), order.getExpressStatusName());
            throw new ServiceResponseException(SysError.ERROR, message);
        }

        // 保存订单退款退货操作日志
        OrderLogs logs = new OrderLogs();
        logs.setCreateIp(IpThreadLocal.get());
        logs.setCreateDate(new Date());
        logs.setOrderNo(order.getOrderNo());
        logs.setType(OrderOpTypeEnum.REQUEST_REFUND_REJECT_SHOPKEEPER.getId());
        logs.setOperatorId(admin.getId());
        logs.setOperatorName(admin.getUserName());
        logs.setRemark(remark);
        orderLogsService.save(logs);

        // 修改订单的退款申请状态为“退款/退货驳回”
        refund.setProgressStatus(RefundProgressEnum.CLOSE.getId());
        refund.setStatus(RefundStatusEnum.REJECT.getId());
        refund.setRemark(remark);
        refund.setUpdateDate(new Date());
        super.edit(refund);

        if (order.getExpressStatus() == ExpressStatusEnum.RETURN_WAIT_RECEIVE.getId()) {
            // 商家待收货 商家拒绝退款 打回物流状态为已收货 支付状态为已支付
            orderService.editExpressStatus(order.getOrderNo(), ExpressStatusEnum.RECEIVED);
            orderService.editPayStatus(order.getOrderNo(), PayStatusEnum.SUCCESS);
            return;
        }
        if (order.getExpressStatus() == ExpressStatusEnum.RETURN_RECEIVED.getId()) {
            // 商家已收货 或许发现商品损坏等其他问题 拒绝退款 直接关闭订单
            orderService.editOrderStatus(order.getOrderNo(), OrderStatusEnum.CLOSE);
            return;
        }
        // 修改支付为已支付状态
        orderService.editPayStatus(order.getOrderNo(), PayStatusEnum.SUCCESS);
    }

    /**
     * 判断退款单是否能被操作
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/10/9 0:51
     */
    private OrderRefund checkRefundForOp(String refundNo) {
        OrderRefund refund = getOrderRefundByRefundNo(refundNo);
        if (!refund.isCanOp()) {
            RefundStatusEnum statusEnum = RefundStatusEnum.getStatus(refund.getStatus());
            String message = String.format("状态为 %s 的退款申请单已被处理!", statusEnum.getName());
            throw new ServiceResponseException(SysError.ERROR, message);
        }
        return refund;
    }

    @Override
    public OrderRefund getOrderRefundByRefundId(String refundId) {
        return refundMapper.getOrderRefundByRefundId(refundId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editOrderRefundStatus(String refundNo, RefundProgressEnum progressEnum) {
        OrderRefund refund = getOrderRefundByRefundNo(refundNo);
        if (refund == null) {
            throw new ServiceResponseException(SysError.PARAM_ERROR, "不存在的退款单信息!");
        }
        refund.setUpdateDate(new Date());
        refund.setProgressStatus(progressEnum.getId());
        super.edit(refund);
    }
}
